/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package models;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import play.db.jpa.Model;

/**
 * 
 * @author Ousama
 */
@Entity
public class Tag extends Model {

	public String name;
	public Date dateOfCreation;
	@ManyToOne
	public IdeaDeveloper creator;
	@ManyToMany(mappedBy = "tags", cascade = CascadeType.PERSIST)
	public List<Idea> ideas = new ArrayList<Idea>();
	@ManyToMany(mappedBy = "tags", cascade = CascadeType.PERSIST)
	public List<Topic> topics = new ArrayList<Topic>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "tag15")
	public List<IdeaDeveloper> followed = new ArrayList<IdeaDeveloper>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "tag16")
	public List<IdeaDeveloper> unfollowed = new ArrayList<IdeaDeveloper>();
	@ManyToMany(mappedBy = "tags", cascade = CascadeType.PERSIST)
	public List<ActionItem> actionitems = new ArrayList<ActionItem>();
	public int relatedItems;

	/**
	 * Constructor for creating tag
	 * 
	 * @param name
	 *            the name of the tag
	 */
	public Tag(String name) {
		this.name = name;
		this.dateOfCreation = new Date();
		this.relatedItems = 0;
		this.save();
		
		Log log = new Log("^ was created.");
		log.ids = this.id + "";
		log.types = "tag";
		log.save();
	}

	/**
	 * Empty constructor for creating tag
	 */
	public Tag() {

	}

	/**
	 * Increment the related items of this tag on every new relation with this
	 * tag
	 * 
	 * @author Zein
	 */
	public void incrementRelatedItems() {
		this.relatedItems++;
		this.save();
	}

	/**
	 * Decrement the related items of this tag on removing any relation with
	 * this tag
	 * 
	 * @author Zein
	 */
	public void decrementRelatedItems() {
		this.relatedItems--;
		this.save();
	}

	/**
	 * Making a new relation between the given Idea and this Tag
	 * 
	 * @author Zein
	 * @param newIdea
	 *            the Idea to be related
	 */

	public void addIdea(Idea newIdea) {
		if (!ideas.contains(newIdea)) {
			ideas.add(newIdea);
			this.incrementRelatedItems();
			this.save();
			
			Log log = new Log("^ is added to ^.");
			log.ids = this.id + "," + newIdea.id;
			log.types = "tag,idea";
			log.save();
		}
	}

	/**
	 * Remove relation between the given Idea and this Tag
	 * 
	 * @author Zein
	 * @param ideaRemoved
	 *            the Idea to be related
	 */

	public void removeIdea(Idea ideaRemoved) {
		if (ideas.contains(ideaRemoved)) {
			ideas.remove(ideaRemoved);
			this.decrementRelatedItems();
			this.save();
			
			Log log = new Log("^ is removed from ^.");
			log.ids = this.id + "," + ideaRemoved.id;
			log.types = "tag,idea";
			log.save();
			
			//this.deleteTag();

		}
	}

	/**
	 * Making a new relation between the given Topic and this Tag
	 * 
	 * @author Zein
	 * @param newTopic
	 *            the Idea to be related
	 */

	public void addTopic(Topic newTopic) {
		if (!topics.contains(newTopic)) {
			topics.add(newTopic);
			this.incrementRelatedItems();
			this.save();
			
			Log log = new Log("^ is added to ^.");
			log.ids = this.id + "," + newTopic.id;
			log.types = "tag,topic";
			log.save();
		}
	}

	/**
	 * Removing relation between the given Topic and this Tag
	 * 
	 * @author Zein
	 * @param topicRemoved
	 *            the topic to be removed
	 */
	public void removeTopic(Topic topicRemoved) {
		if (topics.contains(topicRemoved)) {
			topics.remove(topicRemoved);
			this.decrementRelatedItems();
			this.save();
			
			Log log = new Log("^ is removed from ^.");
			log.ids = this.id + "," + topicRemoved.id;
			log.types = "tag,topic";
			log.save();
			// this.deleteTag();
		}
	}
	
	/**
	 * Making a new relation between the given ActionItem and this Tag
	 * 
	 * @author Zein
	 * @param actionitem
	 *            the ActionItem to be related
	 */

	public void addActionItem(ActionItem actionitem) {
		if (!actionitems.contains(actionitem)) {
			actionitems.add(actionitem);
			this.incrementRelatedItems();
			this.save();
			
			Log log = new Log("^ is added to ^.");
			log.ids = this.id + "," + actionitem.id;
			log.types = "tag,actionitem";
			log.save();
		}
	}

	/**
	 * Remove relation between the given ActionItem and this Tag
	 * 
	 * @author Zein
	 * @param actionitem
	 *            the ActionItem to be related
	 */

	public void removeActionItem(ActionItem actionitem) {
		if (actionitems.contains(actionitem)) {
			actionitems.remove(actionitem);
			this.decrementRelatedItems();
			this.save();
			
			Log log = new Log("^ is removed from ^.");
			log.ids = this.id + "," + actionitem.id;
			log.types = "tag,actionitem";
			log.save();
			
			//this.deleteTag();

		}
	}
	
	/**
	 * Delete this Tag if it is not related to any Idea, Topic, Entity nor
	 * Timline
	 * 
	 * @author Zein
	 */
	public void deleteTag() {
		if (this.relatedItems == 0) {
			this.delete2();
		}
		
		Log log = new Log("^ was deleted.");
		log.ids = this.id + "";
		log.types = "tag";
		log.save();
	}

	/**
	 * adds the tag to the idea given
	 * 
	 * @param idea
	 *            the idea being tagged
	 * 
	 */
	public void TagMe(Idea idea) {
		this.ideas.add(idea);
		this.save();

		idea.tags.add(this);
		idea.save();
		
		Log log = new Log("^ is added to ^.");
		log.ids = this.id + "," + idea.id;
		log.types = "tag,idea";
		log.save();

	}

	/**
	 * delete the tag and all its components
         * @author Zein
	 */
	public void delete2() {
		creator.save();
		for (int i = 0; i < actionitems.size(); i++) {
			actionitems.get(i).tags.remove(this);
			actionitems.get(i).save();
		}
		for (int i = 0; i < followed.size(); i++) {
			followed.get(i).followedTag.remove(this);
			followed.get(i).save();
		}
		for (int i = 0; i < unfollowed.size(); i++) {
			unfollowed.get(i).unfollowedTag.remove(this);
			unfollowed.get(i).save();
		}
		for (int i = 0; i < ideas.size(); i++) {
			ideas.get(i).tags.remove(this);
			ideas.get(i).save();
		}
		for (int i = 0; i < topics.size(); i++) {
			topics.get(i).tags.remove(this);
			topics.get(i).save();
		}
		
		Log log = new Log("^ is deleted.");
		log.ids = this.id + "";
		log.types = "tag";
		log.save();
	}

	/**
	 * takes idea developer and tag and checks if the user was already following
	 * the tag, if yes then return true if not then return false
	 * 
	 * @author nataly.wadie
	 * @param follower
	 *            the idea developer that wants to follow the tag
	 * @param tag
	 *            the tag that the idea developer wants to follow
	 * @return returns strings with the result of the condition checked
	 */
	public static boolean followCheck(IdeaDeveloper follower, Tag tag) {
		return tag.followed.contains(follower);
	}

	/**
	 * takes the idea developer and tag and check if the user is already
	 * following this tag, if yes then do nothing if no then add the user in the
	 * tag followers list in Tag model and add the tag in tags followed list in
	 * idea developer model
	 * 
	 * @author nataly.wadie
	 * @param follower
	 *            idea developer that wants to join the tag
	 * @param tag
	 *            tag the it is being joined by the idea developer
	 */
	public static void followTag(IdeaDeveloper follower, Tag tag) {
		if (!followCheck(follower, tag)) {
			tag.followed.add(follower);
			tag.save();
			follower.followedTag.add(tag);
			follower.save();
			if(tag.unfollowed.contains(follower)){
				tag.unfollowed.remove(follower);
				tag.save();
				follower.unfollowedTag.remove(tag);
				follower.save();
			}
			Log log = new Log("^ followed ^");
			log.ids = follower.id + "," + tag.id;
			log.types = "developer,tag";
		}
	}

	// }

	/**
	 * takes idea developer and tag and checks if the user is already following
	 * the tag then removes him from the tags followers list and removes the tag
	 * from the tags followed list
	 * 
	 * @author nataly.wadie
	 * @param unfollower
	 *            idea developer that doesn't want to receive notifications
	 *            anymore about the tag
	 * @param tag
	 *            tag that will be unfollowed by the idea developer
	 */
	public static void unfollowTag(IdeaDeveloper unfollower, Tag tag) {
		if (followCheck(unfollower, tag)) {
			tag.followed.remove(unfollower);
			tag.save();
			unfollower.followedTag.remove(tag);
			unfollower.save();
			tag.unfollowed.add(unfollower);
			tag.save();
			unfollower.unfollowedTag.add(tag);
			unfollower.save();
			Log log = new Log("^ unfollowed ^");
			log.ids = unfollower.id + "," + tag.id;
			log.types = "developer,tag";
		}
	}
}
